昨天講了 Harness Engineering 要解決的問題,是讓某一類錯誤從此結構上不可能再發生。但「改造環境」聽起來還是很抽象,具體來說,可以動手改造的是哪些東西?今天把它拆成幾個可以指認的實際元件。
最直接、成本也最低的做法,是維護一份 agent 會讀到的指令檔案——像 AGENTS.md、CLAUDE.md 這類專案裡常見的檔案。做法很單純:每次觀察到一個新的失敗模式,就在檔案裡加一條對應的規則。
這正是 Hashimoto 自己在管理 Ghostty 專案時的做法:檔案裡幾乎每一行規則,背後都對應著一次真實發生過的壞行為,而不是憑空想像「agent 可能會做錯什麼」寫出來的預防性條款。這個差異很重要,規則是從真實錯誤反推回來的,而不是一開始就想寫一份「完美」的指令檔案。
指令檔案能解決「agent 讀了規則但選擇忽略」以外的問題,但沒辦法保證 agent 一定會照做,畢竟它還是要靠自己「理解」這份檔案。更進一步的做法,是寫成可以被機械檢查、不需要仰賴模型自己判斷對錯的程式化工具。
舉一個具體例子:對於「這個操作有風險、執行前該不該讓 agent 直接動手」,與其在 prompt 裡寫一句「危險操作前請先詢問」,不如寫成一道會強制擋下來的關卡:
SENSITIVE_TOOLS = {"delete_file", "send_email", "place_order"}
def execute_tool_with_permission(tool_name, tool_input, fn):
if tool_name in SENSITIVE_TOOLS:
print(f"模型想執行「{tool_name}」,參數:{tool_input}")
confirm = input("是否允許執行?(y/n): ")
if confirm.lower() != "y":
return "使用者拒絕執行此操作"
return fn(**tool_input)
這段程式碼不管模型「這次」有沒有記得要小心,只要工具名稱落在 SENSITIVE_TOOLS 裡,就一定會被攔下來詢問——這是結構上的阻止,不是提醒式。同樣的邏輯,也可以用在檢查 agent 產出的格式:例如寫一個小工具,檢查 agent 輸出的 JSON 是不是真的符合預期的 schema,不符合就直接打回去,而不是相信模型自己說「格式沒問題」。
Hashimoto 提到,這類工具通常是「截圖腳本」「跑過濾測試」這種輔助驗證用的小程式,而且經常是搭配指令檔案一起用,工具負責機械式地擋錯,指令檔案負責告訴 agent 為什麼會被擋、下次該怎麼做。
實務上,業界圍繞著這個概念,也延伸出其他常見實踐的方法:
這幾個元件單獨看都不難,指令檔案就是一份文字檔,驗證工具就是一段程式碼。但 Harness Engineering 真正的重點不在「有沒有寫這些東西」,而在於:這些元件有沒有真正對應到觀察到的失敗、有沒有持續被維護。一份從來沒更新過的 AGENTS.md,跟一份每次犯錯都補一條規則的 AGENTS.md,形式一樣,效果天差地遠。
今天把「改造環境」拆成了指令檔案、可機械驗證的工具,以及業界延伸出的架構限制、稽核機制、回饋迴路。這些元件代表了「可以使用那些工具」,現階段大概了解 Harness的目的了,明天分享:如何判斷一個架構,算不算是 Harness Engineering?